home *** CD-ROM | disk | FTP | other *** search
/ Plug-In Power Pack for Netscape Communicator / Plug-In Power Pack for Netscape Communicator.iso / plugins / dataviews / dvtools / examples / windows / dv_mdi / dv_mdi.c next >
Encoding:
C/C++ Source or Header  |  1997-05-08  |  30.1 KB  |  933 lines

  1. /*
  2. |    file name - DV_MDI.c
  3. |=======================================================================
  4. |
  5. |  This program illustrates the creation of an interface using windows
  6. |  routines and incorporating DataViews as part of this interface.
  7. |  In this program MS Windows windows are created in which DataViews views
  8. |  will be displayed. Memory is allocated per window for storage of View
  9. |  specific data such as Screen, Drawport, and View. This data is associated
  10. |  to the MS Window by supplying its handle with SetWindowLong.
  11. |
  12. |  This program illustrates several aspects of integrating DataViews
  13. |  in an MS Windows based application.
  14. |
  15. |  First, the application creates a frame window on which to add many
  16. |  client windows to display DataViews.  The widget is passed to TscOpenSet,
  17. |  which creates a screen object. The window is created explicitly
  18. |  by the application and passed to TscOpenSet.
  19. |
  20. |  Second, this application does not use the DataViews event system to poll
  21. |  for events; it uses the routine GetMessage.  Using this polling
  22. |  method requires the user dispatch the windows message as well as convert the
  23. |  windows message into a location object which can be utilized by the DataViews
  24. |  event handling mechanisms.
  25. |
  26. |  Third, a time-out procedure is set up to update the dynamics of
  27. |  each display whenever the interval of time has past.
  28. |
  29. |  Note: this example will not work properly for views containing
  30. |  DataViews widget-based input objects.
  31. |
  32. |=======================================================================
  33. */
  34. #include <windows.h>
  35. #include <memory.h>
  36.  
  37. /*
  38.  *  DV-Tools header files
  39.  */
  40. #include "std.h"         /* <stdio.h> etc., scalar & macro definitions */
  41. #include "dvstd.h"       /* public types & constants */
  42. #include "dvtools.h"     /* constants used by T routines */
  43. #include "dvGR.h"        /* constants used by window mgt & GR routines */
  44. #include "VOstd.h"       /* constants used by VO & VOob routines */
  45. #include "Tfundecl.h"    /* T routines (screens, drawports & views) */
  46.  
  47. /*
  48.  *  Application specific header files
  49.  */
  50. #include "DV_MDI.h"
  51.  
  52. LRESULT (CALLBACK * MDI_Winproc)() = NULL ;
  53.  
  54. /*
  55.  * Instance data for each MDI child window.
  56.  */
  57. typedef struct _PerWndData
  58.   {
  59.   OBJECT Screen;
  60.   VIEW View;
  61.   DRAWPORT Drawport;
  62.   OBJECT QuitButton;
  63.   UINT idTimer;
  64.   } VIEWDATA, *PVIEWDATA;
  65.  
  66. /*
  67.  * Function Prototypes
  68.  */
  69. HWND InitApplication (HANDLE);
  70. LONG APIENTRY FrameWndProc (HWND, UINT, DWORD, LONG);
  71. LONG APIENTRY ViewWndProc (HWND, UINT, DWORD, LONG);
  72. BOOL APIENTRY CloseEnumProc (HWND, LONG);
  73. BOOL CALLBACK About (HWND, UINT, DWORD, LONG);
  74. BOOL CALLBACK YesNoProc (HWND, UINT, DWORD, LONG);
  75. LOCAL BOOL GetViewDataFromWindow(HWND, PVIEWDATA);
  76. LOCAL BOOL RestartTimerOfWindow(HWND hwnd);
  77. BOOL YesNo (CHAR *);
  78. LOCAL BOOL InitDVWindow(HWND, PVIEWDATA, CHAR *);
  79. LOCAL void TermDVWindow(PVIEWDATA);
  80. LOCAL void TermApplication(void);
  81. LOCAL void UpdateDVwindow(PVIEWDATA);
  82. LOCAL BOOL HandleDVwindowEvents(PVIEWDATA, MSG *);
  83. LOCAL BOOL CreateMDIView(HWND hwnd, CHAR *ViewName);
  84.  
  85. /*
  86.  * Global data
  87.  */
  88. OBJECT   Location;                    /* the DV event representation */
  89. LPCTSTR    YesNoMessage = NULL;        /* message string for YESNO dialog */
  90. HANDLE ghModule;                    /* current executable name */
  91. HWND ghwndFrame = NULL;                /* frame window handle */
  92. HWND ghwndClient = NULL;            /* MDI client window handle */
  93. HMENU  hFrameMenu;                    /* frame menu handle */
  94. HMENU  hFrameMenuWindow;            /* frame menu window handle */
  95. HMENU  hViewMenu;                    /* MDI client menu handle */
  96. HMENU  hViewMenuWindow;                /* MDI client menu window handle */
  97.  
  98. /* This var is set to false when an error message box is displayed then,
  99.  * to true when the dialog exits.
  100.  * We check to see that it is true before redrawing DataViews windows.
  101.  * This prevents an infinit cascade of error messages from overflowing the 
  102.  * stack.
  103.  */
  104. LOCAL BOOL ok_to_draw = TRUE;
  105.  
  106.  
  107. /*-----------------
  108.  *  UpdateDVwindow --  This routine is used to update the dynamics
  109.  *                    of a particular view and drawport in order
  110.  *                    to create frames for annimation.
  111.  */
  112. LOCAL void UpdateDVwindow(PVIEWDATA pViewData)
  113. {
  114.   TviReadData( pViewData->View );
  115.   TdpDrawNext( pViewData->Drawport );
  116. }
  117.  
  118. /*-----------------
  119.  *  HandleDVwindowEvents --  All events received by the windows queue
  120.  *                    are handled as windows events. If any events are
  121.  *                    interpreted by DataViews, they are converted, a
  122.  *                    location object is created, and processed by DataViews
  123.  *                    event handling mechanisms.
  124.  */
  125. LOCAL BOOL HandleDVwindowEvents(PVIEWDATA pViewData, MSG *Message)
  126. {
  127.   WINEVENT we;            /* structure storing details of event */
  128.   CHAR *Name;
  129.   OBJECT SelectedObject;
  130.  
  131.    /*
  132.     *  Convert the Windows event into the DataViews window event structure
  133.     *  (WINEVENT). The using the window event structure set up a
  134.     *  DataViews location object, which is the DataViews representation
  135.     *  of the event.
  136.     */
  137.    (VOID)GRwe_convert( (ADDRESS)Message, &we );   
  138.    (VOID)TloWinEventSetup( Location, &we, (OBJECT)NULL, (DRAWPORT)NULL );
  139.    if ((SelectedObject = TloGetSelectedObject( Location )) != (OBJECT)NULL)
  140.      if (SelectedObject == pViewData->QuitButton)
  141.        return YES;
  142.    /*
  143.     *  DVtools has another way to handle the type of event received based
  144.     *  on information in the location object. An event of this type is for
  145.     *  a DataViews based input object or another independent
  146.     *  object. This event will be dispatched for the user in the
  147.     *  DataViews handler, VUerHandleLocEvent. This is demonstrated in another
  148.     *  DVtools example.
  149.     */
  150.   return NO;
  151. }
  152.  
  153. /*-----------------
  154.  *  InitApplication --  All class data and global data are initialized
  155.  *                    and loaded here.
  156.  */
  157. HWND InitApplication(HANDLE hInstance)
  158. {
  159.   WNDCLASS wc;
  160.   HWND   hwnd   = NULL;
  161.  
  162.   /* Initialize DataViews */
  163.   TInit( NULL, NULL );
  164.  
  165.   /* Reference to current module executing. (.EXE or .DLL) */
  166.   ghModule = GetModuleHandle(NULL);
  167.  
  168.   /* We will need to convert to DataViews events at times so a global
  169.    * location object is created
  170.    */
  171.   if ((Location = VOloCreate()) != (OBJECT)NULL)
  172.     {
  173.     wc.style            = CS_OWNDC;
  174.     wc.lpfnWndProc      = (WNDPROC) FrameWndProc;
  175.     wc.cbClsExtra       = 0;
  176.     wc.cbWndExtra       = sizeof(LONG);
  177.     wc.hInstance        = ghModule;
  178.     wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  179.     wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
  180.     wc.hbrBackground    = (HBRUSH)(COLOR_APPWORKSPACE);
  181.     wc.lpszMenuName     = "FrameMenu";
  182.     wc.lpszClassName    = MDI_FRAME_CLASS_NAME;
  183.  
  184.     /* Register instance of Frame window class. */
  185.     if (RegisterClass(&wc))
  186.       {
  187.       wc.lpfnWndProc      = (WNDPROC) ViewWndProc;
  188.       wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  189.       wc.lpszMenuName     = NULL;
  190.       wc.lpszClassName    = MDI_VIEW_CLASS_NAME;
  191.  
  192.       /* Register instance of MDI window class for view displaying. */
  193.       if (RegisterClass(&wc))
  194.         {
  195.         hFrameMenu = LoadMenu(ghModule, "FrameMenu");
  196.         hViewMenu = LoadMenu(ghModule, "ViewMenu");
  197.         hFrameMenuWindow = GetSubMenu(hFrameMenu, 1);
  198.         hViewMenuWindow = GetSubMenu(hViewMenu, 2);
  199.  
  200.         if ((hwnd = CreateWindowEx(0L, MDI_FRAME_CLASS_NAME, MDI_FRAME_CLASS_NAME,
  201.             WS_OVERLAPPED   | WS_CAPTION     | WS_BORDER       |
  202.             WS_THICKFRAME   | WS_MAXIMIZEBOX | WS_MINIMIZEBOX  |
  203.             WS_CLIPCHILDREN | WS_VISIBLE     | WS_SYSMENU,
  204.             CW_USEDEFAULT,  CW_USEDEFAULT,
  205.             600, 500, NULL, hFrameMenu, hInstance, NULL)) != NULL)
  206.               {
  207.               SetWindowLong(hwnd, GWL_USERDATA, 0L);
  208.               /* set initial focus */
  209.               SetFocus(hwnd);
  210.               }
  211.         }
  212.       }
  213.     }
  214.   return(hwnd);
  215. }
  216.  
  217. /*-----------------
  218.  *  TermApplication --  Free location object and terminate properly from
  219.  *                    DataViews.
  220.  */
  221. void TermApplication(void)
  222.   {
  223.   (VOID)VOloDereference( Location );
  224.   TTerminate();
  225.   }
  226.  
  227. /*-----------------
  228.  *  InitDVWindow --  For each MDI client window used to display a view,
  229.  *                    the DataViews environment must be supplied with the
  230.  *                    appropriate Windows handle. In this example, a view
  231.  *                    is loaded with the passed filename for each client window.
  232.  */
  233. LOCAL BOOL InitDVWindow(HWND hViewWindow, PVIEWDATA pViewData, CHAR *ViewName)
  234.   {
  235.   RECTANGLE Rect = {{-16000, -16000}, {16000, 16000}};
  236.  
  237.     /* Pass the window onto DataViews */
  238.     if ((pViewData->Screen = TscOpenSet( "W:128", NULL,
  239.                          V_WIN32_WINDOW_HANDLE, hViewWindow,
  240.                          V_ACTIVE_CURSOR, V_END_OF_LIST )) != (OBJECT)NULL)
  241.       {
  242.       /* get a pointer to the function that would */
  243.       /* be the window proc for a window created  */
  244.       /* with TscOpenSet                          */
  245.       GRget(V_WIN32_WINDOWPROC, &MDI_Winproc, V_END_OF_LIST);
  246.       GRset(V_WIN32_DOUBLE_BUFFER, TRUE, V_END_OF_LIST);
  247.  
  248.       /* Load the View, Create Drawport and Draw */
  249.       pViewData->View = TviLoad( ViewName );
  250.       TviOpenData( pViewData->View );
  251.       pViewData->Drawport = TdpCreate( pViewData->Screen, pViewData->View,
  252.                                        (RECTANGLE*)NULL, &Rect );
  253.       pViewData->QuitButton = TdrGetNamedObject(TviGetDrawing(pViewData->View), "quit");
  254.       TviReadData( pViewData->View );
  255.       TdpDraw( pViewData->Drawport );
  256.  
  257.       /* Create a Timer for DV dynamic updates */
  258.       pViewData->idTimer = SetTimer( hViewWindow, 0, 100, NULL );
  259.       return(TRUE);
  260.       }
  261.   return(FALSE);
  262.   }
  263.  
  264. /*-----------------
  265.  *  RestartTimerOfWindow --  Restore the timer for DV dynamic updates.
  266.  */
  267. LOCAL BOOL RestartTimerOfWindow(HWND hwnd)
  268.   {
  269.   HANDLE hViewData;
  270.   PVIEWDATA pViewDataFromWindow;
  271.  
  272.   /* Get memory handle for View data associated with window */
  273.   if ((hViewData = (HANDLE) GetWindowLong(hwnd, 0)) != NULL)
  274.     {
  275.     /* Lock memory handle for View data associated with window */
  276.     if ((pViewDataFromWindow = (PVIEWDATA)LocalLock(hViewData)) != NULL)
  277.       pViewDataFromWindow->idTimer = SetTimer( hwnd, 0, 100, NULL );
  278.     LocalUnlock(hViewData);
  279.     }
  280.   }
  281.  
  282. /*-----------------
  283.  *  TermDVWindow --  For each MDI client window used to display a view,
  284.  *                    upon termination the DataViews environment must be
  285.  *                    called in order to deallocate and terminate each view
  286.  *                    properly.
  287.  */
  288. LOCAL void TermDVWindow(PVIEWDATA pViewData)
  289.   {
  290.   TdpDestroy(pViewData->Drawport);
  291.   TviDestroy(pViewData->View);
  292.   TscClose(pViewData->Screen);
  293.   }
  294.  
  295. /*-----------------
  296.  *  GetViewDataFromWindow --  For each MDI client window used to display a view,
  297.  *                    view specific data is encapsulated in the window. This provides
  298.  *                    a mechanism to conveniently associate user data with window data.
  299.  *                    A copy is made of the encapsulated data for comvience only. Since
  300.  *                    Windows NT is a fully preemptive operating system, the timer
  301.  *                    events may occur during the processing of a previous event. This
  302.  *                    new "thread" may cause application code to reenter a DVtools call
  303.  *                    currently being processed. In order to avoid this, the timer
  304.  *                    is "Killed" while in use by GetViewDataFromWindow to lock all
  305.  *                    other requests out.
  306.  */
  307. LOCAL BOOL GetViewDataFromWindow(HWND hwnd, PVIEWDATA pViewData)
  308.   {
  309.   HANDLE hViewData;
  310.   PVIEWDATA pViewDataFromWindow;
  311.  
  312.   /* Get memory handle for View data associated with window */
  313.   if ((hViewData = (HANDLE) GetWindowLong(hwnd, 0)) != NULL)
  314.     {
  315.     /* Lock memory handle for View data associated with window */
  316.     if ((pViewDataFromWindow = (PVIEWDATA)LocalLock(hViewData)) != NULL)
  317.       {
  318.       /*
  319.        * Killing the timer for DV dynamic updates is required since NT
  320.        * is multi-threaded. This will keep the application from updating
  321.        * dynamics while in the process of servicing another message. */
  322.       KillTimer( hwnd, pViewDataFromWindow->idTimer );
  323.  
  324.       memcpy(pViewData, pViewDataFromWindow, sizeof(VIEWDATA));
  325.       LocalUnlock(hViewData);
  326.       return YES;
  327.       }
  328.     else
  329.       MessageBox(ghwndFrame, MDI_ERROR_MEM_LOCK, MDI_ERROR, MB_OK);
  330.     }
  331.   return NO;
  332.   }
  333.  
  334. /*-----------------
  335.  *  CreateMDIView --  For each MDI client window used to display a view,
  336.  *                    we need to allocate memory for view data, create the
  337.  *                    window from the pre-registered class, and supply the
  338.  *                    view data to the window in order to associate it.
  339.  */
  340. LOCAL BOOL CreateMDIView(HWND hwnd, CHAR *ViewName)
  341.   {
  342.   HANDLE hViewData;
  343.   PVIEWDATA  pViewData;
  344.   MDICREATESTRUCT mdicreate;
  345.   HWND hwndChildWindow;
  346.  
  347.   /* Allocate memory for View data to be associated with window */
  348.   if (hViewData = LocalAlloc(LHND, (WORD) sizeof(VIEWDATA))) 
  349.      {
  350.      if ((pViewData = (PVIEWDATA)LocalLock(hViewData)) == NULL)
  351.         MessageBox(ghwndFrame, MDI_ERROR_MEM_LOCK, MDI_ERROR, MB_OK);
  352.  
  353.      mdicreate.szClass = MDI_VIEW_CLASS_NAME;
  354.      mdicreate.szTitle = (LPTSTR)ViewName;
  355.      mdicreate.hOwner  = ghModule;
  356.      mdicreate.x = mdicreate.y = mdicreate.cx = mdicreate.cy = CW_USEDEFAULT;
  357.      mdicreate.style   = 0L;
  358.      /* Supplying the handle of the per MDI View data to the MDI Window */
  359.      mdicreate.lParam  = (LONG) hViewData;
  360.  
  361.      /* Create Child Window */
  362.      if ((hwndChildWindow = (HANDLE) SendMessage(ghwndClient, WM_MDICREATE,
  363.                                 0L, (LONG)(LPMDICREATESTRUCT)&mdicreate)) == NULL)
  364.        {
  365.        MessageBox(ghwndFrame, MDI_ERROR_CREATE_WIN, MDI_ERROR, MB_OK);
  366.        return 0L;
  367.        }
  368.      LocalUnlock(hViewData);
  369.      return YES;
  370.      }
  371.    else
  372.      {
  373.      MessageBox(ghwndFrame, MDI_ERROR_MEM_ALLOC, MDI_ERROR, MB_OK);
  374.      }
  375.   return NO;
  376.   }
  377.  
  378. /*-----------------
  379.  *  WinMain --  All windows applications contain a unique main function. The
  380.  *                only significant difference with this function is that the
  381.  *                the windows message loop is interpreted for MDI accelerator
  382.  *                messages and translated.
  383.  */
  384. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  385.     LPSTR lpCmdLine, int nShowCmd)
  386. {
  387.     MSG    msg;
  388.     HANDLE hAccel;
  389.  
  390.     /* Initialize DataViews and windows. */
  391.     if ((ghwndFrame = InitApplication(hInstance)) != NULL)
  392.         {
  393.         if (!(hAccel = LoadAccelerators (hInstance, MAKEINTRESOURCE(MDI_ACCEL_ID))))
  394.           MessageBox(ghwndFrame, MDI_ERROR_RESLOAD_ACCEL, MDI_ERROR, MB_OK);
  395.  
  396.         /* Here is the windows event loop. */
  397.         while (GetMessage(&msg, NULL, 0, 0))
  398.             {
  399.             if (!TranslateAccelerator(ghwndFrame, hAccel, &msg) &&
  400.                 !TranslateMDISysAccel(ghwndClient, &msg))
  401.                 {
  402.                 TranslateMessage(&msg);
  403.                  DispatchMessage(&msg);
  404.                 }
  405.             }
  406.         /* Normally windows will destroy an attached menu at the time the window
  407.          * is destroyed. In this example the View menu is not attached so it must
  408.          * be destroyed here.
  409.          */
  410.         DestroyMenu(hViewMenu);
  411.     }
  412.   else
  413.     MessageBox(ghwndFrame, MDI_ERROR_WIN_INIT, MDI_ERROR, MB_OK);
  414.   return msg.wParam;
  415.  
  416.     UNREFERENCED_PARAMETER(lpCmdLine);
  417.     UNREFERENCED_PARAMETER(nShowCmd);
  418.     UNREFERENCED_PARAMETER(hInstance);
  419.     UNREFERENCED_PARAMETER(hPrevInstance);
  420. }
  421.  
  422.  
  423. /*-----------------
  424.  *  FrameWndProc --  Each window must have a function that is used to "filter"
  425.  *                    windows messages for all those interested in. This function
  426.  *                    is used for interpreting all messages that are applicable
  427.  *                    to the frame window.
  428.  */
  429. long APIENTRY FrameWndProc(HWND hwnd, UINT message, DWORD wParam,
  430.                            LONG lParam)
  431.   {
  432.     CLIENTCREATESTRUCT clientcreate;
  433.     FARPROC lpfnEnum;
  434.  
  435.     switch (message)
  436.       {
  437.       /* The frame window has been created. */
  438.       case WM_CREATE:
  439.         SetWindowLong(hwnd, 0, (LONG)NULL);
  440.         clientcreate.hWindowMenu  = hFrameMenuWindow;
  441.         clientcreate.idFirstChild = 1;
  442.  
  443.         ghwndClient = CreateWindow("MDICLIENT", NULL,
  444.                                     WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
  445.                                     0,0,0,0,
  446.                                     hwnd, NULL, ghModule, (LPVOID)&clientcreate);
  447.         return 0L;
  448.  
  449.       case WM_ACTIVATE:
  450.           {
  451.               /* this message is sent when the message box is     */
  452.               /* dismissed                                        */
  453.               if (  ( LOWORD(wParam) == WA_ACTIVE ) ||
  454.                     ( LOWORD(wParam) == WA_CLICKACTIVE ) )
  455.                     ok_to_draw = TRUE;
  456.               return 0L;
  457.           }
  458.  
  459.       case WM_CANCELMODE:
  460.           {
  461.               /* this message will be sent when the graph view is */
  462.               /* is sized too small and a message box displays    */
  463.               /* the viewport too small message. redrawing the    */
  464.               /* view while the message box is up will result in  */
  465.               /* an endless stream of errors.                     */
  466.               ok_to_draw = FALSE;
  467.               return 0L;
  468.           }
  469.  
  470.       case WM_COMMAND:
  471.  
  472.         switch (LOWORD(wParam))
  473.           {
  474.           /* Default MDI functionality. */
  475.           case MDI_TILE:
  476.             SendMessage(ghwndClient, WM_MDITILE, 0L, 0L);
  477.             return 0L;
  478.           case MDI_CASCADE:
  479.             SendMessage(ghwndClient, WM_MDICASCADE, 0L, 0L);
  480.             return 0L;
  481.           case MDI_ARRANGE:
  482.             SendMessage(ghwndClient, WM_MDIICONARRANGE, 0L, 0L);
  483.             return 0L;
  484.  
  485.           /* Add MDI View chosen by user from menu options. */
  486.           case MDI_ADD_LIGHTNING_VIEW:
  487.             CreateMDIView(hwnd, LIGHTNING_VIEW_NAME);
  488.             return 0L;
  489.           case MDI_ADD_WINDOW_VIEW:
  490.              CreateMDIView(hwnd, WINDOW_VIEW_NAME);
  491.             return 0L;
  492.           case MDI_ADD_ELLIPSE_VIEW:
  493.             CreateMDIView(hwnd, ELLIPSE_VIEW_NAME);
  494.             return 0L;
  495.  
  496.             /* Launch about dialog. */
  497.             case MDI_ABOUT:
  498.               if (DialogBox(ghModule, MDI_ABOUT_DLG_CLASS_NAME, ghwndFrame, (DLGPROC)About) == -1)
  499.                  MessageBox(ghwndFrame, MDI_ERROR_CREATE_DLG, MDI_ERROR, MB_OK);
  500.               return 0L;
  501.  
  502.             /* A request to destroy has been passed from the exit menu. */
  503.             case MDI_EXIT:
  504.               SendMessage(hwnd, WM_CLOSE, 0, 0L);
  505.               return 0L;
  506.  
  507.             /* Pass appropriate messages to the active child. */
  508.             case MDI_ZOOM_IN:
  509.             case MDI_ZOOM_OUT:
  510.               {
  511.               HWND hActiveChild;
  512.  
  513.               if (hActiveChild = (HANDLE) SendMessage(ghwndClient, WM_MDIGETACTIVE, 0L, 0L))
  514.                 SendMessage(hActiveChild, WM_COMMAND, wParam, lParam);
  515.               return 0L;
  516.               }
  517.  
  518.             /* Inapplicable messages are passed on to parent. */
  519.             default:
  520.               return DefFrameProc(hwnd,  ghwndClient, message, wParam, lParam);
  521.         }
  522.  
  523.       /* A request to close has been passed. */
  524.       case WM_QUERYENDSESSION:
  525.       case WM_CLOSE:
  526.           {
  527.         lpfnEnum = MakeProcInstance((FARPROC)CloseEnumProc, hInst);
  528.         EnumChildWindows(hwnd, lpfnEnum, 0L);
  529.         FreeProcInstance(lpfnEnum);
  530.  
  531.         /* Check to see if this is the icon title window. Do not send message if it is. */
  532.         if (GetWindow(ghwndClient, GW_CHILD) != NULL)
  533.           return 0L;
  534.         SendMessage(hwnd, WM_DESTROY, 0, 0L);
  535.         return 0L;
  536.         }
  537.  
  538.       /* A request to destroy has been passed, possibly from a close message. */
  539.       case WM_DESTROY:
  540.           {
  541.         TermApplication();
  542.         PostQuitMessage(0);
  543.         return 0L;
  544.         }
  545.  
  546.     /* Inapplicable messages are passed on to parent. */
  547.     default:
  548.       return DefFrameProc(hwnd,  ghwndClient, message, wParam, lParam);
  549.     }
  550.   }
  551.  
  552. /*-----------------
  553.  *  CloseEnumProc --  This function sends a WM_MDIRESTORE message to each child
  554.  *                      window followed by a WM_QUERYENDSESSION and possibly a
  555.  *                    WM_MDIDESTROY. This is not done for the icon title window.
  556.  */
  557. BOOL APIENTRY CloseEnumProc(
  558.     HWND hwnd,
  559.     LONG lParam)
  560.   {
  561.   /* Check to see if this is the icon title window. */
  562.   if (GetWindow(hwnd, GW_OWNER))
  563.     return 1;
  564.  
  565.   SendMessage(GetParent(hwnd), WM_MDIRESTORE, (WPARAM)hwnd, 0L);
  566.  
  567.   if (!SendMessage(hwnd, WM_QUERYENDSESSION, 0, 0L))
  568.     return 1;
  569.  
  570.   SendMessage(GetParent(hwnd), WM_MDIDESTROY, (WPARAM)hwnd, 0L);
  571.   return 1;
  572.   }
  573.  
  574. /*-----------------
  575.  *  ViewWndProc --  Each window must have a function that is used to "filter"
  576.  *                    windows messages for all those interested in. This function
  577.  *                    is used for interpreting all messages that are applicable
  578.  *                    to the client or view window. If they are not, then the
  579.  *                    messages are passed onto its parent by NOT returning a 0 but
  580.  *                    returning with DefMDIChildProc.
  581.  */
  582. long APIENTRY ViewWndProc(
  583.     HWND hwnd,
  584.     UINT message,
  585.     DWORD wParam,
  586.     LONG lParam)
  587.   {
  588.  
  589.  
  590.   switch (message)
  591.     {
  592.  
  593.     case WM_COMMAND:
  594.       {
  595.       /* Passed messages from parent. */
  596.       switch (LOWORD(wParam))
  597.         {
  598.         VIEWDATA ViewData;
  599.         DOUBLE    Scale;
  600.  
  601.         case MDI_ZOOM_IN:
  602.           if (GetViewDataFromWindow(hwnd, &ViewData))
  603.             {
  604.             if ((Scale = TdpGetScale(ViewData.Drawport)) < 0.1)
  605.               {
  606.               TdpZoom(ViewData.Drawport, (DOUBLE)1.5);
  607.               TscRedraw(ViewData.Screen, NULL);
  608.               }
  609.             RestartTimerOfWindow(hwnd);
  610.             }
  611.           return 0L;
  612.         case MDI_ZOOM_OUT:
  613.           if (GetViewDataFromWindow(hwnd, &ViewData))
  614.             {
  615.             if ((Scale = TdpGetScale(ViewData.Drawport)) > 0.001)
  616.               {
  617.               TdpZoom(ViewData.Drawport, (DOUBLE)0.75);
  618.               TscRedraw(ViewData.Screen, NULL);
  619.               }
  620.             RestartTimerOfWindow(hwnd);
  621.             }
  622.           return 0L;
  623.         }
  624.       }
  625.  
  626.     /*
  627.      * This message is generated from the timers set upon window initialization
  628.      * for the handling of dynamic updates.
  629.      */
  630.     case WM_TIMER:
  631.       {
  632.       VIEWDATA ViewData;
  633.  
  634.       if (GetViewDataFromWindow(hwnd, &ViewData))
  635.         {
  636.         if (ok_to_draw == TRUE) 
  637.             UpdateDVwindow(&ViewData);
  638.         RestartTimerOfWindow(hwnd);
  639.         }
  640.       return 0L;
  641.       }
  642.  
  643.     /*
  644.      * These messages are assumed to be events that this DataViews
  645.      * example is interested in. At this point is typically where an
  646.      * application will decide whether a message is to be handled by
  647.      * windows code or by DataViews event handling facilities.
  648.      */
  649.     case WM_LBUTTONDOWN:
  650.     case WM_RBUTTONDOWN:
  651.       {
  652.       VIEWDATA ViewData;
  653.       MSG Message;            /* structure storing details of Windows events */
  654.  
  655.       /* Fill structure with appropriate data. */
  656.       Message.hwnd = hwnd;
  657.       Message.message = message;
  658.       Message.wParam = wParam;
  659.       Message.lParam = lParam;
  660.       /*
  661.        * GetMessageTime retrieves the last time posted by the message just
  662.        * retrieved.
  663.        */
  664.       Message.time = GetMessageTime();
  665.       Message.pt.x = LOWORD(lParam);
  666.       Message.pt.y = HIWORD(lParam);
  667.  
  668.       if (GetViewDataFromWindow(hwnd, &ViewData))
  669.         {
  670.         if (HandleDVwindowEvents(&ViewData, &Message))
  671.           {
  672.           /* The YESNO dialog is used to demonstrate DataViews to windows interaction. */
  673.           if (YesNo("Do you really want to close the View window?"))
  674.             SendMessage(hwnd, WM_CLOSE, 0L, 0L);
  675.           }
  676.         RestartTimerOfWindow(hwnd);
  677.         }
  678.       return 0L;
  679.       }
  680.  
  681.     case WM_PAINT:
  682.       {
  683.       PAINTSTRUCT ps;
  684.  
  685.       /* This will call the DV window procedure. This will generate
  686.        * expose and resize events as a DataViews only program would.
  687.        */
  688.       if ( MDI_Winproc != NULL )
  689.         return CallWindowProc(MDI_Winproc, hwnd, message, wParam, lParam );
  690.       BeginPaint(hwnd, &ps);
  691.       EndPaint(hwnd, &ps);
  692.       return 0L;
  693.       }
  694.  
  695.       /* Some portion of the view window has been exposed. VI_EXPOSE comes
  696.        * from the DataViews window procedure's handling of the WM_PAINT message.
  697.        * VI_EXPOSE is defined in dvGR.h.
  698.        */
  699.     case VI_EXPOSE:
  700.       { 
  701.       VIEWDATA ViewData;
  702.       MSG win_msg;
  703.       WINEVENT we;
  704.  
  705.       win_msg.hwnd = hwnd;
  706.       win_msg.message = message;
  707.       win_msg.wParam = wParam;
  708.       win_msg.lParam = lParam;
  709.       
  710.       /* This call must be made on a VI_EXPOSE to keep the DataViews      */
  711.       /* driver in sync with itself. Without this, all heck breaks loose. */
  712.          
  713.       GRwe_convert(&win_msg,&we);
  714.  
  715.       if (GetViewDataFromWindow(hwnd, &ViewData))
  716.         {
  717.         if ( ok_to_draw == TRUE )
  718.             TscRedraw(ViewData.Screen, NULL);
  719.         RestartTimerOfWindow(hwnd);
  720.         }
  721.       return 0L;
  722.       }
  723.  
  724.     /*
  725.      * Potentially, you can set different menus for different MDI
  726.      * views which is currently being active.
  727.      */
  728.     case WM_MDIACTIVATE:
  729.       if ((HWND) lParam == hwnd)
  730.         {
  731.         SendMessage(GetParent(hwnd), WM_MDISETMENU,
  732.                             (DWORD)  hViewMenu,
  733.                             (LONG)   hViewMenuWindow) ;
  734.         DrawMenuBar(GetParent(GetParent(hwnd))) ;
  735.         }
  736.       return 0L;
  737.  
  738.     /* 
  739.      * Whenever the client window is about to be resized, its tracking size may
  740.      * be changed to override the system default for that window. In this case
  741.      * a TscReset will not be able to scale properly to an extremely small window.
  742.      */
  743.     case WM_GETMINMAXINFO:
  744.       {
  745.       LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
  746.  
  747.       if ((lpmmi->ptMinTrackSize.y < 100)||(lpmmi->ptMinTrackSize.x < 100))
  748.         {
  749.         lpmmi->ptMinTrackSize.x = 100;
  750.         lpmmi->ptMinTrackSize.y = 100;
  751.         }
  752.       break;
  753.       }
  754.  
  755.     /*
  756.      * This client window has been resized or the frame window has been resized and
  757.      * this client needs to resize also. VI_RESIZE comes from the DataViews window
  758.      * procedure's handling of the WM_PAINT message. VI_RESIZE is defined in dvGR.h.
  759.      */
  760.     case VI_RESIZE:
  761.     case WM_SIZE:
  762.       { 
  763.       VIEWDATA ViewData;
  764.  
  765.       if (GetViewDataFromWindow(hwnd, &ViewData))
  766.         {
  767.         TscReset(ViewData.Screen);
  768.         RestartTimerOfWindow(hwnd);
  769.         }
  770.       break;
  771.       }
  772.  
  773.     /*
  774.      * Create the control window for this MDI child and saves its handle
  775.      * in the View data structure.
  776.      */
  777.     case WM_CREATE:
  778.       {
  779.       PVIEWDATA           pViewData;
  780.       HANDLE          hViewData;
  781.       CHAR ViewName[MAXSTRING];
  782.  
  783.     /*
  784.      * View data was allocated in CreateMDIView, which is called in the
  785.      * MDI_ADD_XXX_VIEW case of FrameWndProc.
  786.      */
  787.       if (hViewData = (HANDLE) ((LPMDICREATESTRUCT) ((LPCREATESTRUCT) lParam)->lpCreateParams)->lParam)
  788.         {
  789.         if ((pViewData = (PVIEWDATA)LocalLock(hViewData)) == NULL)
  790.           MessageBox(ghwndFrame, MDI_ERROR_MEM_LOCK, MDI_ERROR, MB_OK);
  791.  
  792.         GetWindowText(hwnd, (LPTSTR)ViewName, MAXSTRING);
  793.  
  794.         /*
  795.          * The initialization of the DataViews Windows instance
  796.          * is done at its WM_CREATE message rather than at the time
  797.          * the window create request was made in order to ensure that
  798.          * the view data memory is set by SetWindowLong AFTER the
  799.          * th DV window is initalized by InitDVWindow.
  800.          */
  801.         if (!InitDVWindow(hwnd, pViewData, ViewName))
  802.           MessageBox(hwnd, MDI_ERROR_DV_INIT, MDI_ERROR, MB_OK);
  803.  
  804.         /* Save the handle to VIEWDATA in our window structure */
  805.         SetWindowLong(hwnd, 0, (LONG) hViewData);
  806.         LocalUnlock(hViewData);
  807.         }
  808.       else
  809.         {
  810.         MessageBox(ghwndFrame, MDI_ERROR_MEM_ALLOC, MDI_ERROR, MB_OK);
  811.         }
  812.       break;
  813.       }
  814.  
  815.     /*
  816.      * MDI windows use the WM_QUERYENDSESSION or WM_CLOSE message to see if
  817.      * the application/user is sure they wish to procede with the action.
  818.      * (typically where a "File not saved, are you sure you wish to close?"
  819.      * decision is made)
  820.      */
  821.     case WM_QUERYENDSESSION:
  822.     case WM_CLOSE:
  823.       SendMessage(GetParent(hwnd), WM_MDISETMENU,
  824.                             (DWORD) hFrameMenu,
  825.                             (LONG)  hFrameMenuWindow) ;
  826.       DrawMenuBar(GetParent(GetParent(hwnd))) ;
  827.       break;
  828.  
  829.     /*
  830.      * WM_DESTROY is where the system is comitted to the termination of the
  831.      * window and where the view cleanup must be.
  832.      */
  833.     case WM_DESTROY:
  834.       {
  835.       VIEWDATA ViewData;
  836.  
  837.       /* It is necessary to free and zero the view data associated
  838.        * with this window immediately to avoid further use of this data
  839.        * if events are generated. This is only an issue with Windows NT
  840.        * since it is multi threaded. */
  841.       if (GetViewDataFromWindow(hwnd, &ViewData))
  842.         {
  843.         LocalFree((HANDLE) GetWindowLong(hwnd, 0));
  844.         SetWindowLong(hwnd, 0, (LONG)NULL);
  845.  
  846.         /* Free the View data that is associated with Window. */
  847.         TermDVWindow(&ViewData);
  848.         }
  849.       break;
  850.       }
  851.  
  852.       /* Inapplicable messages are passed on to parent. */
  853.       default:
  854.         return DefMDIChildProc(hwnd, message, wParam, lParam);
  855.     } /* switch */
  856.  
  857.     /* Inapplicable messages are passed on to parent. */
  858.     return DefMDIChildProc(hwnd, message, wParam, lParam);
  859. }
  860.  
  861. /*-----------------
  862.  *  YesNo --  This is a generic dialog used to demonstrate message setting,
  863.  *                    dialog creation, and handling.
  864.  */
  865. BOOL YesNo (CHAR *Message)
  866.   {
  867.   int iReturnValue;
  868.  
  869.   YesNoMessage = (LPCTSTR)Message;
  870.   if ((iReturnValue = DialogBox(ghModule, "YESNO", ghwndFrame, (DLGPROC)YesNoProc)) == -1)
  871.     {
  872.     MessageBox(ghwndFrame, MDI_ERROR_CREATE_DLG, MDI_ERROR, MB_OK);
  873.     return NO;
  874.     }
  875.  
  876.   if (iReturnValue == IDYES)
  877.     return YES;
  878.   return NO;
  879.   }
  880.  
  881. /*-----------------
  882.  *  YesNoProc --  This is a generic dialog proc used to demonstrate message setting,
  883.  *                    dialog creation, and handling.
  884.  */
  885. BOOL CALLBACK YesNoProc (HWND hDlg, UINT message, DWORD wParam,
  886.                          LONG lParam)
  887.   {
  888.   switch (message)
  889.     {
  890.     /*
  891.      * This is the first time the dialog is setup, here the example uses 
  892.      * a predefined message ID for prompting user input.
  893.      */
  894.     case WM_INITDIALOG:
  895.       SetDlgItemText(hDlg, MDI_YESNO_MESSAGE, YesNoMessage);
  896.       return TRUE;
  897.  
  898.     case WM_COMMAND:
  899.       /* Only terminate this dialog with a IDYES or IDNO message. */
  900.       if ((wParam == IDYES)||(wParam == IDNO))
  901.         EndDialog(hDlg, wParam);
  902.       break;
  903.       }
  904.     return FALSE;
  905.  
  906.     UNREFERENCED_PARAMETER(lParam);
  907.     UNREFERENCED_PARAMETER(hDlg);
  908.   }
  909.  
  910. /*-----------------
  911.  *  About --  This is a generic dialog used by most windows applications.
  912.  */
  913. BOOL CALLBACK About (HWND hDlg, UINT message, DWORD wParam,
  914.                      LONG lParam)
  915.   {
  916.   switch (message)
  917.     {
  918.     case WM_INITDIALOG:
  919.       return TRUE;
  920.  
  921.     case WM_COMMAND:
  922.       /* Only terminate this dialog with a IDOK message. */
  923.       if (wParam == IDOK)
  924.         EndDialog(hDlg, wParam);
  925.       break;
  926.       }
  927.     return FALSE;
  928.  
  929.     UNREFERENCED_PARAMETER(lParam);
  930.     UNREFERENCED_PARAMETER(hDlg);
  931.   }
  932.  
  933.